﻿using System;
using Aliyun.OSS.Common;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework.Internal;

namespace Aliyun.OSS.Samples
{
    public class OssObjectInfo
    {
        public string url;
        public long size;
        public string oss_md5;
    }

    /// <summary>
    /// Sample for putting object.
    /// </summary>
    public static class PutObjectManager
    {
        static OssClient client;
        public static void Init(string accessKeyId, string accessKeySecret, string endPoint)
        {
            client = new OssClient(endPoint, accessKeyId, accessKeySecret);
        }

        public static string GetUrl(string bucketName, string key)
        {
            Uri uri = client.GeneratePresignedUri(bucketName, key);
            string url = uri.AbsoluteUri;
            int paramBeginIndex = url.LastIndexOf("?");
            if(paramBeginIndex >= 0)
            {
                url = url.Substring(0, paramBeginIndex);
            }
            return url;
        }

        public static OssObjectInfo PutObjectFromFile(string bucketName, string filePath, string key = null)
        {
            if (key == null)
            {
                key = System.IO.Path.GetFileName(filePath);
            }

            try
            {
                PutObjectResult result = client.PutObject(bucketName, key, filePath);
                OssObjectInfo info = new OssObjectInfo();
                info.oss_md5 = result.ETag;
                info.size = result.ContentLength;
                info.url = GetUrl(bucketName, key);

                Console.WriteLine("Put object succeeded: {0}   {1}", key, info.url);
                return info;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }

            return null;
        }


        public static OssObjectInfo PutObjectFromString(string bucketName, string str, string key)
        {
            try
            {
                MemoryStream stream = new MemoryStream();
                StreamWriter writer = new StreamWriter(stream);
                writer.Write(str);
                writer.Flush();

                PutObjectResult result = client.PutObject(bucketName, key, stream);
                OssObjectInfo info = new OssObjectInfo();
                info.oss_md5 = result.ETag;
                info.size = result.ContentLength;
                info.url = GetUrl(bucketName, key);

                Console.WriteLine("Put object succeeded: {0}   {1}", key, info.url);
                return info;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }

            return null;
        }

        public static bool GetObjectToFile(string bucketName, string filePath, string key = null)
        {
            if (key == null)
            {
                key = System.IO.Path.GetFileName(filePath);
            }

            try
            {
                OssObject obj = client.GetObject(bucketName, key);
                using(System.IO.Stream input = obj.Content)
                {
                    long size = obj.ContentLength;
                    string tempFilePath = System.IO.Path.GetTempFileName();
                    using(System.IO.FileStream output = new System.IO.FileStream(tempFilePath, System.IO.FileMode.OpenOrCreate))
                    {
                        int sum = 0;
                        int len = 1024 * 1024;
                        byte[] data = new byte[len];
                        while(true)
                        {
                            int realLen = input.Read(data, 0, len);


                            if(realLen < 0)
                            {
                                if(size != sum)
                                {
                                    throw new System.Exception("Get object failed: " + key + "   " + filePath);
                                }
                                break;
                            }

                            output.Write(data, 0, realLen);
                            sum += realLen;



                            if(sum >= size)
                            {
                                break;
                            }
                        }

                        output.Flush(true);
                        System.IO.File.Copy(tempFilePath, filePath, true);
                        Console.WriteLine("Get object succeeded: " + size + "  " + sum + "  " + filePath + "   " + key);
//                        Console.WriteLine("Get object succeeded:  " +  key, filePath);
                    }
                }



                return true;
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
//            catch (Exception ex)
//            {
//                Console.WriteLine("Failed with error info: {0}", ex.Message);
//            }

            return false;
        }


        public static string GetObjectToString(string bucketName,  string key)
        {
            string outStr = null;

            try
            {
                OssObject obj = client.GetObject(bucketName, key);
                using (System.IO.Stream input = obj.Content)
                {
                    long size = obj.ContentLength;
                    string tempFilePath = System.IO.Path.GetTempFileName();
                    using (System.IO.MemoryStream output = new System.IO.MemoryStream())
                    {
                        int sum = 0;
                        int len = 1024 * 1024;
                        byte[] data = new byte[len];
                        while (true)
                        {
                            int realLen = input.Read(data, 0, len);


                            if (realLen < 0)
                            {
                                if (size != sum)
                                {
                                    throw new System.Exception("Get object failed: " + key);
                                }
                                break;
                            }

                            output.Write(data, 0, realLen);
                            sum += realLen;



                            if (sum >= size)
                            {
                                break;
                            }
                        }

                        output.Position = 0;

                        // Use StreamReader to read the contents of the MemoryStream as a string
                        using (StreamReader reader = new StreamReader(output, System.Text.Encoding.UTF8))
                        {
                            outStr = reader.ReadToEnd();
                            //Console.WriteLine("Get object succeeded: " + size + "  " + sum + "  " + s + "   " + key);
                        }
                    }
                }
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            //            catch (Exception ex)
            //            {
            //                Console.WriteLine("Failed with error info: {0}", ex.Message);
            //            }

            return outStr;
        }

        public static void DeleteObject(string bucketName, string key)
        {
            try
            {
                client.DeleteObject(bucketName, key);

                Console.WriteLine("Delete object:{0} succeeded: {1}", key);
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }

        public static void GetObjects(string bucketName, string prefix, System.Action<ObjectListing> callBack)
        {
            ListObjectsRequest request = new ListObjectsRequest(bucketName);
            request.Prefix = prefix;
            while(true)
            {
                try
                {
                    ObjectListing objs = client.ListObjects(request);
                    callBack(objs);

                    if(!objs.IsTruncated)
                    {
                        return;
                    }

                    request.Marker = objs.NextMarker;
                }
                catch (OssException ex)
                {
                    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Failed with error info: {0}", ex.Message);
                }
            }
        }
    }

    public class UploadFileToAliOssTool
    {
        /// <summary>
        /// SDK的示例程序
        /// </summary>
        public static void Upload(string accessKeyId, string accessKeySecret, string endPoint, string bucketName, string srcFilePath, string destFilePath)
        {
            PutObjectManager.Init(accessKeyId, accessKeySecret, endPoint);

            if (System.IO.Directory.Exists(srcFilePath))
            {
                Console.WriteLine("start Put Directory: " + srcFilePath + " | " + destFilePath);

                srcFilePath = srcFilePath.Replace('\\', '/');
                string[] filePaths = System.IO.Directory.GetFiles(srcFilePath, "*", System.IO.SearchOption.AllDirectories);
                foreach (var p in filePaths)
                {
                    string tp = p.Replace('\\', '/');
                    string tempDest = (destFilePath + "/" + tp.Substring(srcFilePath.Length + 1)).Replace('\\', '/');
                    Console.WriteLine("srcPath: " + tp);
                    Console.WriteLine("srcDest: " + tempDest);
                    string url = PutObjectFromFile(bucketName, tp, tempDest);
                }
            }
            else
            {
                string url = PutObjectFromFile(bucketName, srcFilePath, destFilePath);
            }
            


            //if (string.IsNullOrEmpty(url))
            //{
            //    throw new System.Exception("put object failed: " + accessKeyId + " | " + accessKeySecret + " | " + endPoint + " | " + url + "   " + bucketName + "  " + srcFilePath + "  " + destFilePath);
            //}
            //else
            //{
            //    string host = PutObjectSample2.GetBucketHost(bucketName);
            //    Console.WriteLine(url);
            //}
        }
            
        public static string PutObjectFromFile(string bucketName, string filePath, string key)
        {
            PutObjectManager.PutObjectFromFile(bucketName, filePath, key);
            return null;
        }

    }


}